<?php

declare(strict_types=1);

namespace SixShop\Wangdian\Auth;

use SixShop\Wangdian\Config\Config;

/**
 * Handles API signature generation and authentication
 */
class Authenticator
{
    public function __construct(
        private readonly Config $config
    ) {
    }

    /**
     * Generate API signature for the request
     */
    public function generateSignature(array $params): string
    {
        // Remove existing sign parameter if present
        unset($params['sign']);

        // Add required authentication parameters
        $params['sid'] = $this->config->sid;
        $params['appkey'] = $this->config->appKey;
        $params['timestamp'] = time();

        // Pack data according to Wangdian specification
        $packedData = $this->packData($params);

        // Generate MD5 signature
        return md5($packedData . $this->config->appSecret);
    }

    /**
     * Add authentication parameters to request
     */
    public function addAuthParams(array $params): array
    {
        $params['sid'] = $this->config->sid;
        $params['appkey'] = $this->config->appKey;
        $params['timestamp'] = time();
        $params['sign'] = $this->generateSignature($params);

        return $params;
    }

    /**
     * Pack data according to Wangdian specification
     * Format: length-key:length-value;length-key:length-value...
     */
    private function packData(array $params): string
    {
        ksort($params);
        $packed = [];

        foreach ($params as $key => $value) {
            if ($key === 'sign') {
                continue;
            }

            if (!empty($packed)) {
                $packed[] = ';';
            }

            $keyLength = mb_strlen((string) $key, 'UTF-8');
            $valueLength = mb_strlen((string) $value, 'UTF-8');

            $packed[] = sprintf('%02d', $keyLength);
            $packed[] = '-';
            $packed[] = $key;
            $packed[] = ':';
            $packed[] = sprintf('%04d', $valueLength);
            $packed[] = '-';
            $packed[] = $value;
        }

        return implode('', $packed);
    }

    /**
     * Validate request parameters
     */
    public function validateParams(array $params): void
    {
        $requiredKeys = ['sid', 'appkey', 'timestamp'];

        foreach ($requiredKeys as $key) {
            if (!isset($params[$key]) || empty($params[$key])) {
                throw new \InvalidArgumentException("Missing required parameter: {$key}");
            }
        }
    }
}